| Miles Sound System SDK 7.2a |
The Sony PS2 has two audio hardware cores, called the "SPUs", that can each decode 24 ADPCM sound samples. Each SPU can also play one uncompressed PCM stream (which Miles and Bink use for their high-level audio output). As an alternative to the Miles and Bink high-level APIs, the RAD_IOP Hardware Voice API may be used to control the 48 ADPCM voices directly.
The ADPCM hardware is nice because it doesn't use any EE or IOP cycles or any EE or IOP RAM. There are downsides, though -- the hardware is pretty basic. It can only play mono ADPCM voices, and runtime control is rudimentary.
The SPUs are easy to program because they are so simple. Each SPU plays its 24 voices constantly. In fact, you don't really start and stop this hardware - if you want to stop audio playback, for example, you simply turn down the volume or point the playback at silence data. This is kind of weird, but since it's hardware, it costs nothing.
Our SPU API operates on the voices at a very low level, and it operates on them in parallel. That is, every SPU voice function can operate on any one or all of the 48 voices at once. For example, you can set the pitch of all 48 voices in a single call, if you choose to.
Since the voice resources are fixed, you don't "allocate" a voice - you simply start using its bit mask. For example, the bit mask for voice 23 is "1 << 23", so you just use that constant when you want to do something with voice 23. If you want to find a voice that isn't playing anything, then you can use the RAD_IOPQueueAsyncSPUGlobalState and RAD_IOPFindNonPlayingVoiceMask functions to find one, or you can just keep track of which voices are active as you use them. This is a lower-level approach than an API like Miles offers, but it's also easy, fast and reflects the way that the hardware actually works.
Similar to the non-allocation-based voice policy, the Sony system software doesn't use an API for allocating and freeing SPU RAM. You are expected to manage this yourself. SPU RAM for game use starts at address 0x5100 and ends at address 0x1fffff (roughly 2 MB). Most games simply start allocating memory with a linear allocator at offset 0x5100 at the start of each level, and then flush back to 0x5100 at the start of the next level.
You can use the RAD_IOP async IO functions (described in the previous chapter) to load the actual audio data files. Sony calls SPU-compatible audio files "VAG" files, and they use a simple ADPCM compression scheme. You use the VAGEdit utility to convert WAV files into VAG files. VAG files are very simple - there is a 48-byte header, followed by the sound data itself. Most people don't even read the header, since all you need is the pitch and that's generally a game-wide setting. So, most games simply skip the 48-byte header completely, and just load the audio data.
Although this all seems very low-level, it is actually quite simple (and easier to understand in code than the docs). See the MilesPS2.cpp example program for a demonstration.
The rest of this section will describe the SPU voice APIs.
| The RAD_IOP SPU Hardware Voice API for the Sony PS2 | |
|---|---|
| RAD_IOPSetSPUVoiceStartAddress | sets the address to play from for one or more SPU voices. |
| RAD_IOPSetSPUVoiceLoopAddress | sets the address to loop back to for one or more SPU voices. |
| RAD_IOPSetSPUVoiceVolume | sets the volume for one or more SPU voices. |
| RAD_IOPSetSPUVoicePitch | sets the pitch for one or more SPU voices. |
| RAD_IOPSetSPUVoiceADSR | sets the envelope for one or more SPU voices. |
| RAD_IOPSetSPUVoiceMixOnOff | sets the mix on-off routing for one or more SPU voices. |
| RAD_IOPSetSPUVoiceOnOff | starts or stops the playback of one or more SPU voices. |
| RAD_IOPQueueAsyncSPUVoiceState | asynchronously queries the state of an SPU voice. |
| RAD_IOP_SPU_VOICE_STATE | is a structure used with the RAD_IOPQueueAsyncSPUVoiceState function. |
| RAD_IOP_SPU_VOICE_STATE_CALLBACK | points to a function that will be called when the async query completes. |
| RAD_IOPQueueAsyncSPUGlobalState | asynchronously queries the state of the SPU cores. |
| RAD_IOP_SPU_GLOBAL_STATE | is a structure used with the RAD_IOPQueueAsyncSPUGlobalState function. |
| RAD_IOP_SPU_GLOBAL_STATE_CALLBACK | points to a function that will be called when the async query completes. |
| RAD_IOPFindNonPlayingVoiceMask | returns a bitmask that corresponds to a single non-playing voice. |
For technical support, e-mail Miles3@radgametools.com
© Copyright 1991-2007 RAD Game Tools, Inc. All Rights Reserved.